<?php
/**
 * ck框架 3.0程序入口
 * @copyright (c) 2012 http://www.ckframework.com All rights reserved
 * @license http://www.apache.org/licenses/LICENSE-2.0
 * @author wujibing<283109896@qq.com>
 */
//定义框架常量
if(PHP_VERSION < 5.3)
{
	define('__DIR__', dirname(__FILE__));
}
define('CK_DIR',str_replace('\\', '/', __DIR__).'/');
define('CK_EXCEPTION_DIR',CK_DIR.'exception/');
define('CK_DB_DIR',CK_DIR.'db/');
define('CK_DB_RESOLVE_DIR', CK_DB_DIR.'resolve/');
define('CK_LANG_DIR',CK_DIR.'lang/');
define('IN_CKFRAMEWORK', true);
/**
 * CK框架ckApplication类。
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @author    wujibing<283109896@qq.com>
 * @version   1.0
 */
class ckApplication extends ckEventObejct
{
    /**
     * application初始化后的事件
     * @var string
     */
    const EVENT_APP_INIT = 'APP_INIT';
    /**
     * application加载配置文件后的事件
     * @var string
     */
    const EVENT_APP_LOADCONFIG = 'APP_LOAD_CONFIG';
    /**
     * 初始化
     * @param string $appName 项目名称
     * @param string $appDir 项目的目录地址
     */
    public function __construct($appName,$appDir)
    {
        define('CK_APPLICATION_DIR', $appDir);
        define('CK_APPLICATION_NAME', $appName);
    }
    /**
     * 执行程序
     */
    public function main()
    {
    	//判断用户定义了DATA目录没
    	!defined('CK_APPLICATION_DATA_DIR') ? define('CK_APPLICATION_DATA_DIR', CK_APPLICATION_DIR.'data/') : '';
    	//判断用户定义了运行时文件没
    	!defined('CK_RUN_TIME_FILE') ? define('CK_RUN_TIME_FILE', CK_APPLICATION_DATA_DIR.'~runTime.php') : '';
    	if(!file_exists(CK_RUN_TIME_FILE))
        {
        	$this->startCompile();	
        } else 
        {
        	include CK_RUN_TIME_FILE;
        }
        !defined('CK_APPLICATION_CONFIG_FILE') ? define('CK_APPLICATION_CONFIG_FILE', CK_APPLICATION_DIR.'config.ck') : '';
        //加载配置文件
        config::loadConfig(CK_APPLICATION_CONFIG_FILE);
        config::check();
        //加载配置文件后执行的事件
        $this->run(self::EVENT_APP_LOADCONFIG);
        //定义APPLICATION的DATA目录
        //加载语言包
        lang::loadCKLang(config::$configObject->APP_LANG);
        lang::loadLang(config::$configObject->APP_LANG);
        //设置时区
        date_default_timezone_set(config::$configObject->TIME_ZONE);
        //定义系统时间
        define('SYSTIME', time());
        //定义出错报告级别
        error_reporting(config::$configObject->CK_DEVELOP_NOW ? E_ERROR | E_WARNING | E_PARSE : 0);
        //过滤数据
        $this->formatData();
        //寻找控制器并允许
       $this->runApp(); 
    }
    #########################################静态函数 用于全局 主要兼容2.0下版本################################################
    public static function createUrl($action,$method='')
    {
        return '?'. config::$configObject->ACTION_NAME . '=' . $action . '&' .config::$configObject->METHOD_NAME . '=' . $method;
    }
    /**
     * 载入模块
     * @param string $moduleName
     * @throws base_Exception
     * @return module
     */
    public static function loadM($moduleName)
    {
        $moduleName .= '_M';
        if(!isset($_ENV[$moduleName]) || !$_ENV[$moduleName] instanceof  module)
        {
            $_ENV[$moduleName] = new $moduleName();
            if(!$_ENV[$moduleName] instanceof module)
            {
                throw new base_Exception(lang::getLang('__MODULE_DON_NOT_INSTANCEOF_MODULE__',array($moduleName)),__LINE__);
            }
        }
        return $_ENV[$moduleName];
    }
    /**
     * 自动加载
     * @param string $objName
     * @throws base_Exception
     */
    public static function autoload($objName)
    {
        $classExplode = explode('_', $objName);
        $classNameEnd = end($classExplode);
        $fileName = '';
        switch ($classNameEnd)
        {
            case 'Exception':
                $fileName = CK_EXCEPTION_DIR . $objName .'.class.php';
                break;
            case 'db':
                $fileName = CK_DB_DIR . 'db.' . $classExplode[0] .'.class.php';
                break;
            case 'Resolve':
                $fileName = CK_DB_RESOLVE_DIR . 'db.resolve.' .$classExplode[0] . '.class.php';
                break;
            case 'M':
                $fileName = CK_APPLICATION_DIR . 'lib/module/' . $classExplode[0] . '_' .$classExplode[1] . '_module.class.php';
                break;
            case 'A':
                $fileName = CK_APPLICATION_DIR . 'lib/action/' . $classExplode[0] . '_' .$classExplode[1] . '_action.class.php';
                break;
            case 'P'://插件
                $fileName = CK_APPLICATION_DIR.'lib/pluigs/'.$objName.'.class.php';
                break;
            default:
                $fileName = CK_DIR . 'lib/' .$objName. '.class.php';
        }
        if (!file_exists($fileName))
        {
            throw new base_Exception(lang::getLang('__NOT__FOUND__CLASS_FILE__',array($fileName)));
        }
        require $fileName;
    }
    /**
     * 消息提示
     * @param string $message 消息内容
     * @param string $jumpUrl 跳转内容
     */
    public static function showMessage($message,$jumpUrl = '')
    {
        include CK_APPLICATION_DATA_DIR .'/'.config::$configObject->APP_MESSAGE_PAGE;
        exit();
    }
    /**
     * 设置404
     * @param unknown_type $message
     */
    public static function  set404($message)
    {
    	header('HTTP/1.1 404 Not Found');
    	header('Status: 404 Not Found');
    	include CK_APPLICATION_DATA_DIR .'/'.config::$configObject->APP_404_PAGE;
    	exit();
    }
    #########################################静态函数 用于全局################################################
    /**
     * 寻找控制器并运行
     */
    private function runApp()
    {
        $actionName = config::$configObject->ACTION_NAME;
        $methodName = config::$configObject->METHOD_NAME;
        $actionValue = isset($_GET[$actionName]) && $_GET[$actionName] ? $_GET[$actionName] : (isset($_POST[$actionName]) && $_POST[$actionName] ? $_POST[$actionName] : config::$configObject->DEFAULT_ACTION);
        $methodValue = isset($_GET[$methodName]) && $_GET[$methodName] ? $_GET[$methodName] : (isset($_POST[$methodName]) && $_POST[$methodName] ? $_POST[$methodName] : config::$configObject->DEFAULT_METHOD);
        config::$configObject->ckAction = $actionValue;
        config::$configObject->ckMethod = $methodValue;
        //完成初始化的事件
        $this->run(self::EVENT_APP_INIT);
        $className = $actionValue.'_'.CK_APPLICATION_NAME.'_A';
        $action = new $className();
        if (!method_exists($action, $methodValue))
        {
            self::set404(lang::getLang('__ILLEGAL_TO_SUBMIT__'), '/');
        }
        $ref = new ReflectionMethod($action, $methodValue);
        if (!$ref->isPublic()  || $ref->isAbstract())
        {
            self::set404(lang::getLang('__ILLEGAL_TO_SUBMIT__'), '/');
        }
        $action->actionInit($actionValue, $methodValue);
        $action->checkMethodName();
        //判断有没Module 有Module加载Module
        if (! $action->hasModule())
        {
            $action->loadModule();
        }
        $action->$methodValue();
    }
    /**
     * 过滤get post等数据
     */
    private function formatData()
    {
        if(get_magic_quotes_gpc())
        {
            format::htmlSpecialchars($_REQUEST,true);
            format::htmlSpecialchars($_POST);
            format::htmlSpecialchars($_GET);
            format::addslashes($_COOKIE);
        } else
        {
            format::addslashes($_REQUEST,true);
            format::addslashes($_POST,true);
            format::addslashes($_GET,true);
            format::addslashes($_COOKIE);
        }
    }
	private function startCompile ()
	{
		$tmpFile = '';
		$compileStr = '';
		//需要写入的文件名
		$fileArr = array(
			'lib/action.class.php',
			'lib/module.class.php',
			'lib/dbProxy2.class.php',
			'lib/file.class.php',
			'lib/config.class.php',
			'lib/dir.class.php',
			'lib/view.class.php',
			'lib/page.class.php',
			'lib/lang.class.php',
			'lib/filter.class.php',
			'lib/format.class.php',
			'exception/base_Exception.class.php',
			'exception/queryFaild_sql_Exception.class.php',
			'db/db.IDb.class.php',
			'db/db.mysql.class.php',
			'db/resolve/db.resolve.mysql.class.php'
		);
		foreach ($fileArr as $v)
		{
			$tmpFile = CK_DIR . $v;
			$compileStr .= file_get_contents($tmpFile);
		}
		//正则替换掉
		$compileStr = preg_replace('$/\*\*{0,1}.+?\*/$s', '', $compileStr);
		$compileStr = preg_replace('$\/\/.+?(\r|\n|\r\n)$', '', $compileStr);
		$compileStr = preg_replace('$\<\?php(\r|\n|\r\n)$', '', $compileStr);
		$compileStr = preg_replace('$\r|\n|\x9|\/\/$', '', $compileStr);
		file_put_contents(CK_RUN_TIME_FILE, '<?php defined(\'IN_CKFRAMEWORK\') or die(\'bad Request\'); ' . $compileStr);
	}
}

/**
 * CK框架事件类。所有需要事件的类都可以继承该类
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @author    wujibing<283109896@qq.com>
 * @version   1.0
 */
abstract class ckEventObejct
{
    /**
     * 事件数组
     * @var array
     */
    protected $_events = array();
    /**
     * 增加一个事件
     * <code>
     * $this->attach('删除的事件',function(){//do something;})
     * $this->attach('删除的事件',array(object,'method',array(函数参数)))
     * //执行RUN
     * $this->run('删除的事件');
     * </code>
     * @param string $method 事件名称
     * @param mixed $callBack 事件调用方法
     */
    public function attach($method,$callBack)
    {
        if(!isset($this->_events[$method]))
        {
            $this->_events[$method] = array();
        }
        $this->_events[$method][] = $callBack;
    }
    /**
     * 通知事件
     * @param string $method 事件名称
     * @param array $args 事件参数
     */
    protected function run($method,$args = array())
    {
        if(isset($this->_events[$method]) && is_array($this->_events[$method]) && $this->_events[$method])
        {
            foreach ($this->_events[$method] as $key => $value)
            {
                call_user_func_array($value, $args);
            }
        }
    }
    /**
     * 删除事件
     * @param string $method 事件名
     */
    public function detach($method)
    {
        if(isset($this->_events[$method]))
        {
            $this->_events[$method] = array();
        }
    }
}
spl_autoload_register(array('ckApplication','autoload'));